#include <cstdlib>
#include <iostream>
#include <string>
#include <math.h>
#include <GL/glut.h>
#include <GL/glu.h>
#include "glm.h"
#include "camera.h"
#include "cenario.h"

#define SOMA_PITCH 10.0
#define SOMA_ROLL 10.0
#define SOMA_YAW 10.0
#define SOMA_VELOC 1.0
#define SOMA_ALTURA 1
#define PERSP_AT_X 2.0
#define PERSP_AT_Y 0.5
#define PERSP_AT_Z 0.0
#define PERSP_TO_X 1.0
#define PERSP_TO_Y 0.25
#define PERSP_TO_Z 0.0


int state[35];

typedef struct{
        double velocidade;
        int altura;
        int deslX;
        int deslZ;
        double pitch;     //empina
        double roll;      //gira asa
        double yaw;       //vira
        GLboolean noChao;
        GLMmodel *model;
} Aviao;

Aviao boing;

void iniciaAviao(){
     
     boing.altura=0;
     boing.deslX=0;
     boing.deslZ=0;
     boing.noChao=true;
     boing.pitch=0.0;
     boing.roll=0.0;
     boing.yaw=0.0;
     boing.velocidade=0.0;
     
     }

Observador CameraPersp, CameraOrto;

//converte graus pra radianos
double toRad(double gr){
       return (gr*M_PI/180.0);
       }

void desenhaAviao(){
     
     glPushMatrix();
     glTranslatef(boing.deslX, boing.altura, boing.deslZ);
     
     glPushMatrix();
     //rotacoes
     glRotatef(boing.roll, 1.0, 0.0, 0.0);
     glRotatef(boing.yaw, 0.0, 1.0, 0.0);
     glRotatef(boing.pitch, 0.0, 0.0, 1.0);
     
     glTranslatef(0.31,-0.21,0.32);                         //aviao já vem posicionado errado
     glmDraw(boing.model, GLM_SMOOTH | GLM_MATERIAL);
     
     glPopMatrix();
     glPopMatrix();
     }

int detectaColisao(){
     
     if(boing.altura < -0.5){
          return 1;
          }
     if((boing.deslX >= -3.5 && boing.deslX <= -6.5) && (boing.altura <= 2.5)
                      && (boing.deslZ >= 1.5 && boing.deslZ <= 4.5)){                  //colisao com cubo
       return 1;
       }
     if((boing.deslX >= -0.5 && boing.deslX <= 20.5) && (boing.altura <= 10.5)
                      && (boing.deslZ >= 19.5 && boing.deslZ <= 40.5)){                  //colisao com esfera
       return 1;
       }
     return 0;
     }


void ilumina(){
     
     // caracteristicas da fonte de luz
	 GLfloat light_ambient[] = { 0.5, 0.5, 0.5, 0.0 };
	 GLfloat light_diffuse[] = { 0.7, 0.7, 0.7, 1.0 };
	 GLfloat light_specular[] = { 0.6, 0.6, 0.6, 1.0 };
	 GLfloat light_position[] = { 0.0, 100.0, 0.0, 0.0 };
     
     // Ativa o uso da luz ambiente 
	 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_ambient);
     
     // define os parâmetros da luz de número 0
	 glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
	 glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
	 glLightfv(GL_LIGHT0, GL_POSITION, light_position);
     
	 // Habilita a definição da cor do material a partir da cor corrente
	 glEnable(GL_COLOR_MATERIAL);
	 //Habilita o uso de iluminação
	 glEnable(GL_LIGHTING);
	 // Habilita a luz de número 0
	 glEnable(GL_LIGHT0);
     
     glShadeModel(GL_SMOOTH);
     glEnable (GL_CULL_FACE);
     glEnable (GL_DEPTH_TEST);
  }

void desenhaAviao2(){
     
     glPushMatrix();
     glTranslatef(boing.deslX, 10.5, boing.deslZ+1);
     
     glPushMatrix();
     glRotatef(boing.yaw, 0.0, 1.0, 0.0);
     
     glmDraw(boing.model, GLM_SMOOTH | GLM_MATERIAL);
     
     glPopMatrix();
     glPopMatrix();
     
     }

void iniciaCameras(){
     
     CameraPersp.atx=PERSP_AT_X;
     CameraPersp.aty=PERSP_AT_Y;
     CameraPersp.atz=PERSP_AT_Z;
     CameraPersp.tox=PERSP_TO_X;
     CameraPersp.toy=PERSP_TO_Y;
     CameraPersp.toz=PERSP_TO_Z;
     CameraPersp.angle=60.0;
     CameraPersp.fAspect=4.0/3.0;
     
     CameraOrto.atx=0.0;
     CameraOrto.aty=1.0;
     CameraOrto.atz=0.0;
     CameraOrto.tox=0.0;
     CameraOrto.toy=0.0;
     CameraOrto.toz=0.0;
     CameraOrto.minX=-2.0;
     CameraOrto.maxX=2.0;
     CameraOrto.minY=-1.5;
     CameraOrto.maxY=1.5;
     CameraOrto.near_plane=-10.0;
     CameraOrto.far_plane=10.0;
     CameraOrto.incremento=0.0;
     }

void translateCameras(){
     
     CameraPersp.atx=PERSP_AT_X*cos(toRad(boing.yaw)) + PERSP_AT_Z*sin(toRad(boing.yaw)) + boing.deslX;
     CameraPersp.aty=PERSP_AT_Y+boing.altura;
     CameraPersp.atz=-PERSP_AT_X*sin(toRad(boing.yaw)) + PERSP_AT_Z*cos(toRad(boing.yaw)) + boing.deslZ;
     CameraPersp.tox=PERSP_TO_X*cos(toRad(boing.yaw)) + PERSP_TO_Z*sin(toRad(boing.yaw)) + boing.deslX;
     CameraPersp.toy=PERSP_TO_Y+boing.altura;
     CameraPersp.toz=-PERSP_TO_X*sin(toRad(boing.yaw)) + PERSP_TO_Z*cos(toRad(boing.yaw)) + boing.deslZ;
     
     CameraOrto.atx=boing.deslX;
     CameraOrto.aty=1.0+boing.altura;
     CameraOrto.atz=boing.deslZ;
     CameraOrto.tox=boing.deslX;
     CameraOrto.toy=boing.altura;
     CameraOrto.toz=boing.deslZ;
     }

void display(){
     
     glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT);
     
     glViewport(0, 0, 800, 600);          //viewport 1
     PerspectiveViewing(CameraPersp);
     
     desenhaCenario();
     desenhaAviao();
     
     glViewport(550, 350, 250, 250);            //viewport 2
     OrthoViewing(CameraOrto);
     
     desenhaCenario();
     desenhaAviao();
     
     if(birdEye){
       
       desenhaAviao2();
       
       }
     
     glutPostRedisplay();
     
     glutSwapBuffers();
     }

void SetupRC(){
     
     glClearColor(0.5, 0.7, 1.0, 1.0);
     glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT);
     
     iniciaCameras();
     iniciaAviao();
     ilumina();
     
     }

void KeyOperations(){
     
     if (state[23]){
          boing.pitch += SOMA_PITCH;
        }
     if (state[19]){
          boing.pitch -= SOMA_PITCH;
        }
     if (state[4]){
          boing.roll -= SOMA_ROLL;
        }
     if (state[1]){
          boing.roll += SOMA_ROLL;
        }
     if(state[2]){
          birdEye=!birdEye;
          }
     if (state[30]){
          boing.velocidade += SOMA_VELOC;
        }
     if (state[29]){
          boing.velocidade -= SOMA_VELOC;
        }
     if (state[28]){
          boing.yaw -= SOMA_YAW;
        }
     if (state[27]){
          boing.yaw += SOMA_YAW;
          }
     if (state[17]){
        exit(0);
        }
     
     if(boing.pitch >= 360.0)
       boing.pitch -= 360.0;
     if(boing.pitch < 0.0)
       boing.pitch += 360.0;
     
     if(boing.roll >= 360.0)
       boing.roll -= 360.0;
     if(boing.roll < 0.0)
       boing.roll += 360.0;
     
     if(boing.yaw >= 360.0)
       boing.yaw -= 360.0;
     if(boing.yaw < 0.0)
       boing.yaw += 360.0;
     
     
     
     }

void idleF(){
     
    static double tempoanterior=0;
     double tempo;
     double tempopassado;
     
     tempo=glutGet(GLUT_ELAPSED_TIME);
     tempopassado = (tempo-tempoanterior)/1000.0;
     
     if(tempopassado > 0.1){
       KeyOperations();
       
       boing.deslX=boing.velocidade*cos(toRad(boing.pitch))*(-cos(toRad(boing.yaw)));
       boing.altura=boing.velocidade*sin(-toRad(boing.pitch));
       boing.deslZ=boing.velocidade*cos(toRad(boing.pitch))*sin(toRad(boing.yaw));
       
       if(detectaColisao())
          exit(1);
       
       translateCameras();
       
       tempoanterior=tempo;
       }
     
     }

void keyPressed(unsigned char key, int x, int y){
     if(key=='a')
       state[1]=1;
     if(key=='b')
       state[2]=1;
     if(key=='d')
       state[4]=1;
     if(key=='s')
       state[19]=1;
     if(key=='w')
       state[23]=1;
     if(key=='q')
       state[17]=1;
     
     }

void SpecialKey(int key, int x, int y){
      if(key==GLUT_KEY_LEFT)
        state[27]=1;
      if(key==GLUT_KEY_RIGHT)
        state[28]=1;
      if(key==GLUT_KEY_DOWN)
        state[29]=1;
      if(key==GLUT_KEY_UP)
        state[30]=1;
     }

void SpecialRelease(int key, int x, int y){
      if(key==GLUT_KEY_LEFT)
        state[27]=0;
      if(key==GLUT_KEY_RIGHT)
        state[28]=0;
      if(key==GLUT_KEY_DOWN)
        state[29]=0;
      if(key==GLUT_KEY_UP)
        state[30]=0;
     
     }

void keyRelease(unsigned char key, int x, int y) {
     if(key=='a')
       state[1]=0;
     if(key=='b')
       state[2]=0;
     if(key=='d')
       state[4]=0;
     if(key=='s')
       state[19]=0;
     if(key=='w')
       state[23]=0;
     
     
     }

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutInitWindowPosition(15,15);
    glutCreateWindow("Fly Simulation");
    
    boing.model=(GLMmodel*)malloc(sizeof(GLMmodel));
    boing.model=glmReadOBJ("B_727_200.obj");
    glmScale(boing.model, 0.01);
    
    glutKeyboardFunc(keyPressed);
    glutSpecialFunc(SpecialKey);
    glutSpecialUpFunc(SpecialRelease);
    glutKeyboardUpFunc(keyRelease);
    SetupRC();
    glutDisplayFunc(display);
    glutIdleFunc(idleF);
    
    glutMainLoop();
    return EXIT_SUCCESS;
}
